package org.mushroomdb.transaction;

import java.util.Iterator;
import java.util.List;

import org.mushroomdb.catalog.Column;
import org.mushroomdb.catalog.Register;
import org.mushroomdb.catalog.Table;
import org.mushroomdb.catalog.WriteBackRegister;
import org.mushroomdb.exception.RDBMSRuntimeException;
import org.mushroomdb.interceptor.AbstractInterceptor;
import org.mushroomdb.lock.LockException;
import org.mushroomdb.lock.LockService;
import org.mushroomdb.lock.locktypes.Lock;
import org.mushroomdb.lock.locktypes.RegisterLock;
import org.mushroomdb.service.ServiceManager;

/**
 * @author Tomas
 * 
 *  
 */
public class ResourceControlInterceptor extends AbstractInterceptor {

    public void beforeInsert(Register register, Table table) {

        TransactionService trxService = (TransactionService) ServiceManager
                .getInstance().getService(TransactionService.class);
        Transaction trx = trxService.getCurrentTrx();
        if (trx != null && !trx.isStacked() && !sysTable(table)) {
            trx.setStackedOp();
            LockService lockService = (LockService) ServiceManager
                    .getInstance().getService(LockService.class);
            Lock lock = null;
            try {
                lock = lockService.lock(table);
            } catch (LockException e) {
                e.printStackTrace();
                throw new RDBMSRuntimeException(e);
            }
            appendLock(lock);
            appendTrxResource((TransactionalResource) table);
            trx.removeStackedOp();
        }

    }

    /**
     * @param register
     * @return
     */

    public void beforeUpdate(Register register, int columnIndex, Object value,
            Table table) {

        TransactionService trxService = (TransactionService) ServiceManager
                .getInstance().getService(TransactionService.class);
        Transaction trx = trxService.getCurrentTrx();

        if (trx != null && !trx.isStacked() && !sysRegister(register)) {
            List resources = trx.getResources();
            if (!resources.contains(table)) {

                trx.setStackedOp();
                LockService lockService = (LockService) ServiceManager
                        .getInstance().getService(LockService.class);
                Lock lock = null;
                try {
                    lock = lockService.lock(register);
                } catch (LockException e) {
                    //TODO CheckThis
                    throw new RDBMSRuntimeException(e);
                }
                appendLock(lock);
                appendTrxResource((TransactionalResource) register);
                trx.removeStackedOp();

            }
        }
    }

    /**
     * @param register
     * @return
     */
    private boolean sysRegister(Register register) {
        Iterator iter = register.getColumns();
        boolean flag = true;
        while (iter.hasNext() && flag) {
            Column column = (Column) iter.next();
            Table table = column.getTable();
            String tableName = table.getName();
            if (tableName.startsWith("SYS")) {
                return true;
            }
        }
        return false;
    }

    /**
     * @param table
     * @return
     */
    private boolean sysTable(Table table) {
        String tableName = table.getName();
        return tableName.startsWith("SYS");

    }

    public void beforeDelete(Register register, Table table) {
        TransactionService trxService = (TransactionService) ServiceManager
                .getInstance().getService(TransactionService.class);
        Transaction trx = trxService.getCurrentTrx();

        if (trx != null && !trx.isStacked() && !sysRegister(register)) {
            List resources = trx.getResources();
            if (!resources.contains(table)) {

                trx.setStackedOp();
                LockService lockService = (LockService) ServiceManager
                        .getInstance().getService(LockService.class);
                Lock lock = null;
                try {
                    lock = lockService.lock(register);
                } catch (LockException e) {
                    //TODO CheckThis
                    throw new RDBMSRuntimeException(e);
                }
                appendLock(lock);
                appendTrxResource((TransactionalResource) register);
                trx.removeStackedOp();

            }
        }
    }

    private void appendTrxResource(TransactionalResource resource) {

        TransactionService transactionService = (TransactionService) ServiceManager
                .getInstance().getService(TransactionService.class);
        Transaction trx = transactionService.getCurrentTrx();
        trx.append(resource);

    }

    private void appendLock(Lock lock) {
        if (lock != null) {
            TransactionService transactionService = (TransactionService) ServiceManager
                    .getInstance().getService(TransactionService.class);
            Transaction trx = transactionService.getCurrentTrx();
            trx.appendLock(lock);
        }
    }

}
